package com.hgxd.fillter;

import com.alibaba.fastjson.JSON;
import com.hgxd.entity.pojo.SysUser;
import com.hgxd.entity.res.ResQOQAnalysis;
import com.hgxd.result.Result;
import com.hgxd.result.ResultCodeEnum;
import com.hgxd.util.ResponseUtil;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author wtf
 * @create 2023-07-24 18:45
 * @description : 过滤器，用来拦截验证请求是否有token（认证解析token过滤器）
 */
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private StringRedisTemplate stringRedisTemplate;

    public TokenAuthenticationFilter(StringRedisTemplate redisTemplate) {
        this.stringRedisTemplate = redisTemplate;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        logger.info("uri:"+request.getRequestURI());
        StringBuffer requestURL = request.getRequestURL();
        System.out.println("requestURL = " + requestURL);

        //如果是登录接口，直接放行
        if("/api/login".equals(request.getRequestURI())) {
            chain.doFilter(request, response);
            return;
        }
        //如果是日志记录，直接放行
        if("/api/setOperationForLogin".equals(request.getRequestURI())) {
            chain.doFilter(request, response);
            return;
        }
        UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
        if(null != authentication) {
            SecurityContextHolder.getContext().setAuthentication(authentication);
            //放行请求
            chain.doFilter(request, response);
        } else {
            ResponseUtil.out(response, Result.build(null, ResultCodeEnum.PERMISSION));
        }
    }

    /**
     * 非登录接口在此进行认证
     * @param request
     * @return
     */
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        // token置于header里
        String token = request.getHeader("token");

        if (!StringUtils.isEmpty(token)) {
            String s = stringRedisTemplate.boundValueOps(token).get();
            SysUser sysUser = JSON.parseObject(s, SysUser.class);
//            SysUser sysUser = (SysUser)redisTemplate.boundValueOps(token).get();
            if (null != sysUser) {
                if (null != sysUser.getUserPermsList() && sysUser.getUserPermsList().size() > 0) {
                    //1)获取当前用户的所有perms集合
                    //sysUser.getUserPermsList()
                    //2)进行过滤，如果是bnt，那么就留下。其他两种（目录和菜单）直接忽略
                    // 目录和菜单这两种类型的SysMenu记录的perms这一列是空.只有按钮类型的SysMenu才有perms
                    //.stream().filter(code -> !Strin2gUtils.isEmpty(code.trim()))
                    //3)需要将按钮类型的SysMenu封装成对应的SimpleGrantedAuthority对象
                    //.map(code -> new SimpleGrantedAuthority(code.trim()))
                    List<SimpleGrantedAuthority> authorities = sysUser.getUserPermsList()
                            .stream().filter(code -> !StringUtils.isEmpty(code.trim()))
                            .map(code -> new SimpleGrantedAuthority(code.trim()))
                            .collect(Collectors.toList());
                    //返回一个认证之后包含权限的对象
                    return new UsernamePasswordAuthenticationToken(sysUser.getUsername(), null, authorities);
                } else {
                    //返回一个认证之后没有权限的对象
                    return new UsernamePasswordAuthenticationToken(sysUser.getUsername(), null, Collections.emptyList());
                }
            }
        }
        return null;
    }
}

